/**
 * @file 	 mbrtu.c
 * @brief
 * @author 	 wenbo
 * @version  1.0
 * @date 	 2023-03-21
 *
 * @copyright Copyright (c) 2023  YGL
 *
 */
#include "mbrtu.h"
#include "mbcrc.h"
#include "string.h"
#include "fmb_port.h"

/* ----------------------- Defines ------------------------------------------*/
#define MB_SER_PDU_SIZE_MIN     4       /*!< Minimum size of a Modbus RTU frame. */
#define MB_SER_PDU_SIZE_MAX     256     /*!< Maximum size of a Modbus RTU frame. */
#define MB_SER_PDU_SIZE_CRC     2       /*!< Size of CRC field in PDU. */
#define MB_SER_PDU_ADDR_OFF     0       /*!< Offset of slave address in Ser-PDU. */
#define MB_SER_PDU_PDU_OFF      1       /*!< Offset of Modbus-PDU in Ser-PDU. */

#define LOGI 

typedef struct
{
	void* pBuf;
	USHORT startAddr;
	USHORT size;
} reg_map_t;

struct mbSlave_ctx_st {
	UCHAR  ucRTUBuf[MB_SER_PDU_SIZE_MAX];
	USHORT usSndBufferCount;
	USHORT usRcvBufferPos;
	UCHAR mbAddress;
	UCHAR mbPort;

	reg_map_t inputReg;
	reg_map_t holdReg;
	reg_map_t coilsReg;
	reg_map_t discreteReg;

	inputReg_r_cb_t* inputReg_r_cb_list;
	holdReg_rw_cb_t* holdReg_rw_cb_list;
	coilsReg_rw_cb_t* coilsReg_rw_cb_list;
	discreteReg_r_cb_t* discreteReg_r_cb_list;

	eMBRegInputCB_t eMBRegInputCB;
	eMBRegHoldingCB_t eMBRegHoldingCB;
	eMBRegCoilsCB_t eMBRegCoilsCB;
	eMBRegDiscreteCB_t eMBRegDiscreteCB;
};

// 协议栈平台适配层需要实现的接口,这里弱定义
eMB_WEAK eMBErrorCode eMBRTU_PortInit(UCHAR port, ULONG baudRate, eMBParity parity)
{
	// ...用户层需重定义此接口
	return MB_EPORTERR;
}
eMB_WEAK void eMBRTU_PortDeInit(UCHAR port)
{
	// ...用户层需重定义此接口
}
eMB_WEAK eMBErrorCode eMBRTU_SendCB(UCHAR port, UCHAR* pData, ULONG size)
{
	// ...用户层需重定义此接口
	return MB_EPORTERR;
}
eMB_WEAK void* eMB_Malloc(ULONG size)
{
	// ...用户层需重定义此接口
	return NULL;
}
eMB_WEAK void eMB_Free(void* p)
{
	// ...用户层需重定义此接口
}

/* ----------------------- Start implementation -----------------------------*/
static eMBErrorCode eMBRTUInit(mbSlave_ctx* const ctx, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity)
{
	assert(ctx);
	ctx->mbAddress = ucSlaveAddress;
	ctx->mbPort = ucPort;
	return eMBRTU_PortInit(ucPort, ulBaudRate, eParity);
}

static eMBErrorCode eMBRTUReceive(mbSlave_ctx* const ctx, UCHAR* pucRcvAddress, UCHAR** pucFrame, USHORT* pusLength)
{
	eMBErrorCode	eStatus = MB_ENOERR;
	assert(ctx);
	assert(ctx->usRcvBufferPos < MB_SER_PDU_SIZE_MAX);

	/* Length and CRC check */
	if ((ctx->usRcvBufferPos >= MB_SER_PDU_SIZE_MIN) && (usMBCRC16((UCHAR*) ctx->ucRTUBuf, ctx->usRcvBufferPos) == 0)) {
		/* Save the address field. All frames are passed to the upper layed
		 * and the decision if a frame is used is done there.
		 */
		*pucRcvAddress = ctx->ucRTUBuf[MB_SER_PDU_ADDR_OFF];

		/* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
		 * size of address field and CRC checksum.
		 */
		*pusLength = (USHORT) (ctx->usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC);

		/* Return the start of the Modbus PDU to the caller. */
		*pucFrame = (UCHAR*) &ctx->ucRTUBuf[MB_SER_PDU_PDU_OFF];
	}
	else {
		eStatus = MB_EIO;
	}

	return eStatus;
}

static eMBErrorCode eMBRTUSend(mbSlave_ctx* const ctx, const UCHAR* pucFrame, USHORT usLength)
{
	eMBErrorCode	eStatus = MB_ENOERR;
	USHORT		  usCRC16;
	assert(ctx);

	/* First byte before the Modbus-PDU is the slave address. */
	UCHAR* pucSndBufferCur = (UCHAR*) pucFrame - 1;
	USHORT usSndBufferCount = 1;

	/* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
	pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ctx->mbAddress;
	usSndBufferCount += usLength;

	/* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */
	usCRC16 = usMBCRC16((UCHAR*) pucSndBufferCur, usSndBufferCount);
	ctx->ucRTUBuf[usSndBufferCount++] = (UCHAR) (usCRC16 & 0xFF);
	ctx->ucRTUBuf[usSndBufferCount++] = (UCHAR) (usCRC16 >> 8);

	eStatus = eMBRTU_SendCB(ctx->mbPort, (UCHAR*) ctx->ucRTUBuf, usSndBufferCount);
	return eStatus;
}

eMBErrorCode eMBRTU_Process(mbSlave_ctx* const ctx, UCHAR* pData, USHORT size)
{
	UCHAR* ucMBFrame;
	UCHAR			ucRcvAddress;
	UCHAR			ucFunctionCode;
	USHORT		    usLength;
	eMBException 	eException;
	eMBErrorCode	eStatus = MB_ENOERR;

	assert(ctx);

	if (!pData) {
		return MB_EIO;
	}

	memcpy((UCHAR*) ctx->ucRTUBuf, pData, size);
	ctx->usRcvBufferPos = size;


	/* 对当前数据帧进行CRC校验 */
	eStatus = eMBRTUReceive(ctx, &ucRcvAddress, &ucMBFrame, &usLength);
	if (eStatus == MB_ENOERR) {
		/* Check if the frame is for us. If not ignore the frame. */
		if ((ucRcvAddress == ctx->mbAddress) || (ucRcvAddress == MB_ADDRESS_BROADCAST)) {
			ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
			eException = MB_EX_ILLEGAL_FUNCTION;

			// /* 根据其功能码回调相应处理函数 */
			switch (ucFunctionCode) {

#if MB_FUNC_OTHER_REP_SLAVEID_ENABLED > 0
			case MB_FUNC_OTHER_REPORT_SLAVEID:
				eException = eMBFuncReportSlaveID(ucMBFrame, &usLength);
				break;
#endif
#if MB_FUNC_READ_INPUT_ENABLED > 0
			case MB_FUNC_READ_INPUT_REGISTER:
				eException = eMBFuncReadInputRegister(ctx, ucMBFrame, &usLength, ctx->eMBRegInputCB);
				break;
#endif
#if MB_FUNC_READ_HOLDING_ENABLED > 0
			case MB_FUNC_READ_HOLDING_REGISTER:
				eException = eMBFuncReadHoldingRegister(ctx, ucMBFrame, &usLength, ctx->eMBRegHoldingCB);
				break;
#endif
#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
			case MB_FUNC_WRITE_MULTIPLE_REGISTERS:
				eException = eMBFuncWriteMultipleHoldingRegister(ctx, ucMBFrame, &usLength, ctx->eMBRegHoldingCB);
				break;
#endif
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
			case MB_FUNC_WRITE_REGISTER:
				eException = eMBFuncWriteHoldingRegister(ctx, ucMBFrame, &usLength, ctx->eMBRegHoldingCB);
				break;
#endif
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
			case MB_FUNC_READWRITE_MULTIPLE_REGISTERS:
				eException = eMBFuncReadWriteMultipleHoldingRegister(ctx, ucMBFrame, &usLength, ctx->eMBRegHoldingCB);
				break;
#endif
#if MB_FUNC_READ_COILS_ENABLED > 0
			case MB_FUNC_READ_COILS:
				eException = eMBFuncReadCoils(ctx, ucMBFrame, &usLength, ctx->eMBRegCoilsCB);
				break;
#endif
#if MB_FUNC_WRITE_COIL_ENABLED > 0
			case MB_FUNC_WRITE_SINGLE_COIL:
				eException = eMBFuncWriteCoil(ctx, ucMBFrame, &usLength, ctx->eMBRegCoilsCB);
				break;
#endif
#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
			case MB_FUNC_WRITE_MULTIPLE_COILS:
				eException = eMBFuncWriteMultipleCoils(ctx, ucMBFrame, &usLength, ctx->eMBRegCoilsCB);
				break;
#endif
#if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0
			case MB_FUNC_READ_DISCRETE_INPUTS:
				eException = eMBFuncReadDiscreteInputs(ctx, ucMBFrame, &usLength, ctx->eMBRegDiscreteCB);
				break;
#endif
			default:
				break;
			}

			/* If the request was not sent to the broadcast address we
			 * return a reply. */
			if (ucRcvAddress != MB_ADDRESS_BROADCAST) {
				if (eException != MB_EX_NONE) {
					/* An exception occured. Build an error frame. */
					usLength = 0;
					ucMBFrame[usLength++] = (UCHAR) (ucFunctionCode | MB_FUNC_ERROR);
					ucMBFrame[usLength++] = eException;
				}

				eStatus = eMBRTUSend(ctx, ucMBFrame, usLength);
			}
		}
	}
	return MB_ENOERR;
}

mbSlave_ctx* mbSlave_creat(UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity)
{
	mbSlave_ctx* ctx = eMB_Malloc(sizeof(mbSlave_ctx));
	if (ctx) {
		if (MB_ENOERR == eMBRTUInit(ctx, ucSlaveAddress, ucPort, ulBaudRate, eParity)) {
			mbSlave_register_reg_callback(ctx, NULL, NULL, NULL, NULL);
			ctx->inputReg_r_cb_list = NULL;
			ctx->holdReg_rw_cb_list = NULL;
			ctx->coilsReg_rw_cb_list = NULL;
			ctx->discreteReg_r_cb_list = NULL;
			return ctx;
		}
		eMB_Free(ctx);
	}
	return NULL;
}

void mbSlave_distory(mbSlave_ctx* ctx)
{
	if (ctx) {
		eMBRTU_PortDeInit(ctx->mbPort);
		eMB_Free(ctx);
	}
}

/**********************************************************************************/
/**
 * @brief	   输入寄存器回调,输入寄存器可读,但不可写.
 * @param[in]	pucRegBuffer		寄存器数据指针
 * @param[in]	usAddress			寄存器起始地址
 * @param[in]	usNRegs				寄存器长度
 * @return		eMBErrorCode		寄存器状态
 */
static eMBErrorCode eMBRegInput_origin_callback(void* const handle, UCHAR* pucRegBuffer, USHORT usAddress, USHORT usNRegs)
{
	eMBErrorCode eStatus = MB_ENOERR;
	mbSlave_ctx* const ctx = (mbSlave_ctx*) handle;
	int16_t iRegIndex;

	if (!ctx->inputReg.pBuf || 0 == ctx->inputReg.size) {
		return MB_EPORTERR;
	}

	USHORT* const usRegInputBuf = (USHORT*) ctx->inputReg.pBuf;

	usAddress--;
	if ((usAddress >= ctx->inputReg.startAddr) && (usAddress + usNRegs <= ctx->inputReg.startAddr + ctx->inputReg.size)) {

		iRegIndex = (int16_t) (usAddress - ctx->inputReg.startAddr);

		while (usNRegs > 0) {
			if (ctx->inputReg_r_cb_list && ctx->inputReg_r_cb_list[iRegIndex]) {
				ctx->inputReg_r_cb_list[iRegIndex](iRegIndex + ctx->inputReg.startAddr, usRegInputBuf[iRegIndex]);
			}
			*pucRegBuffer++ = (UCHAR) (usRegInputBuf[iRegIndex] >> 8);
			*pucRegBuffer++ = (UCHAR) (usRegInputBuf[iRegIndex] & 0xFF);
			iRegIndex++;
			usNRegs--;
		}
	}
	else {
		eStatus = MB_ENOREG;
	}

	LOGI("eMBRegInputCB: usAddress: 0x%04X, usNRegs: 0x%04X", usAddress, usNRegs);
	return eStatus;
}

/**
 * @brief	   保持寄存器处理函数,保持寄存器可读可写
 * @param[in]	pucRegBuffer		寄存器数据指针
 * @param[in]	usAddress			寄存器起始地址
 * @param[in]	usNRegs				寄存器长度
 * @param[in]	eMode				操作方式,读或者写
 * @return		eMBErrorCode		寄存器状态
 */
static eMBErrorCode eMBRegHolding_origin_callback(void* const handle, UCHAR* pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode)
{
	eMBErrorCode eStatus = MB_ENOERR;
	mbSlave_ctx* const ctx = (mbSlave_ctx*) handle;
	int16_t iRegIndex;

	if (!ctx->holdReg.pBuf || 0 == ctx->holdReg.size) {
		return MB_EPORTERR;
	}

	USHORT* const usRegHoldingBuf = (USHORT*) ctx->holdReg.pBuf;

	usAddress--;
	if ((usAddress >= ctx->holdReg.startAddr) && (usAddress + usNRegs <= ctx->holdReg.startAddr + ctx->holdReg.size)) {

		iRegIndex = (int16_t) (usAddress - ctx->holdReg.startAddr);

		switch (eMode) {
		case MB_REG_READ:
			while (usNRegs > 0) {
				if (ctx->holdReg_rw_cb_list && ctx->holdReg_rw_cb_list[iRegIndex]) {
					ctx->holdReg_rw_cb_list[iRegIndex](iRegIndex + ctx->inputReg.startAddr, usRegHoldingBuf[iRegIndex], FALSE);
				}
				*pucRegBuffer++ = (UCHAR) (usRegHoldingBuf[iRegIndex] >> 8);
				*pucRegBuffer++ = (UCHAR) (usRegHoldingBuf[iRegIndex] & 0xFF);
				iRegIndex++;
				usNRegs--;
			}
			break;

		case MB_REG_WRITE:
			while (usNRegs > 0) {
				usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
				usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
				if (ctx->holdReg_rw_cb_list && ctx->holdReg_rw_cb_list[iRegIndex]) {
					ctx->holdReg_rw_cb_list[iRegIndex](iRegIndex + ctx->inputReg.startAddr, usRegHoldingBuf[iRegIndex], TRUE);
				}
				iRegIndex++;
				usNRegs--;
			}
			break;
		}
	}
	else {
		eStatus = MB_ENOREG;
	}
	LOGI("eMBRegHoldingCB: usAddress: 0x%04X, usNRegs: 0x%04X, eMode: %s", usAddress, usNRegs, eMode == MB_REG_READ ? "Read" : "write");
	return eStatus;
}

/**
 * @brief	   线圈寄存器处理函数,线圈寄存器可读可写
 * @param[in]	pucRegBuffer		寄存器数据指针
 * @param[in]	usAddress			寄存器起始地址
 * @param[in]	usNCoils			寄存器长度
 * @param[in]	eMode				操作方式,读或者写
 * @return		eMBErrorCode		寄存器状态
 */
static eMBErrorCode eMBRegCoils_origin_callback(void* const handle, UCHAR* pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode)
{
	eMBErrorCode eStatus = MB_ENOERR;
	mbSlave_ctx* const ctx = (mbSlave_ctx*) handle;
	SHORT iNCoils = (SHORT) usNCoils;
	USHORT usBitOffset;

	if (!ctx->coilsReg.pBuf || 0 == ctx->coilsReg.size) {
		return MB_EPORTERR;
	}

	UCHAR* const ucRegCoilsBuf = (UCHAR*) ctx->coilsReg.pBuf;

	usAddress--;
	if ((usAddress >= ctx->coilsReg.startAddr) && (usAddress + usNCoils <= ctx->coilsReg.startAddr + ctx->coilsReg.size)) {

		usBitOffset = (usAddress - ctx->coilsReg.startAddr);
		switch (eMode) {

		case MB_REG_READ:
			while (iNCoils > 0) {
				for (size_t i = 0; i < (iNCoils > 8 ? 8 : iNCoils); i++) {
					if (ctx->coilsReg_rw_cb_list && ctx->coilsReg_rw_cb_list[usBitOffset + i]) {
						BOOL bitState = ucRegCoilsBuf[(usBitOffset + i) / 8] & (1 << ((usBitOffset + i) % 8));
						ctx->coilsReg_rw_cb_list[usBitOffset + i](usBitOffset + i + ctx->inputReg.startAddr, bitState, FALSE);
					}
				}
				*pucRegBuffer++ = xMBUtilGetBits(ucRegCoilsBuf, usBitOffset, (UCHAR) (iNCoils > 8 ? 8 : iNCoils));
				iNCoils -= 8;
				usBitOffset += 8;
			}
			break;

		case MB_REG_WRITE:
			while (iNCoils > 0) {
				for (size_t i = 0; i < (iNCoils > 8 ? 8 : iNCoils); i++) {
					if (ctx->coilsReg_rw_cb_list && ctx->coilsReg_rw_cb_list[usBitOffset + i]) {
						BOOL bitState = (*pucRegBuffer) & (1 << i);
						ctx->coilsReg_rw_cb_list[usBitOffset + i](usBitOffset + i + ctx->inputReg.startAddr, bitState, TRUE);
					}
				}
				xMBUtilSetBits(ucRegCoilsBuf, usBitOffset, (UCHAR) (iNCoils > 8 ? 8 : iNCoils), *pucRegBuffer++);
				iNCoils -= 8;
				usBitOffset += 8;
			}
			break;
		}
	}
	else {
		eStatus = MB_ENOREG;
	}
	LOGI("eMBRegCoilsCB: usAddress: 0x%04X, usNRegs: 0x%04X, eMode: %d", usAddress, usNCoils, eMode);
	return eStatus;
}

/**
 * @brief	   开关输入寄存器处理函数,开关输入寄存器,可读
 * @param[in]	pucRegBuffer		寄存器数据指针
 * @param[in]	usAddress			寄存器起始地址
 * @param[in]	usNDiscrete			寄存器长度
 * @return		eMBErrorCode		寄存器状态
 */
static eMBErrorCode eMBRegDiscrete_origin_callback(void* const handle, UCHAR* pucRegBuffer, USHORT usAddress, USHORT usNDiscrete)
{
	eMBErrorCode eStatus = MB_ENOERR;
	mbSlave_ctx* const ctx = (mbSlave_ctx*) handle;
	USHORT iNDiscrete = usNDiscrete;
	USHORT usBitOffset;

	if (!ctx->discreteReg.pBuf || 0 == ctx->discreteReg.size) {
		return MB_EPORTERR;
	}

	UCHAR* const ucRegDiscreteBuf = (UCHAR*) ctx->discreteReg.pBuf;

	usAddress--;
	if ((usAddress >= ctx->discreteReg.startAddr) && (usAddress + usNDiscrete <= ctx->discreteReg.startAddr + ctx->discreteReg.size)) {

		usBitOffset = (USHORT) (usAddress - ctx->discreteReg.startAddr);

		while (iNDiscrete > 0) {
			for (size_t i = 0; i < (iNDiscrete > 8 ? 8 : iNDiscrete); i++) {
				if (ctx->discreteReg_r_cb_list && ctx->discreteReg_r_cb_list[usBitOffset + i]) {
					BOOL bitState = ucRegDiscreteBuf[(usBitOffset + i) / 8] & (1 << (usBitOffset + i) % 8);
					ctx->discreteReg_r_cb_list[usBitOffset + i](usBitOffset + i + ctx->inputReg.startAddr, bitState);
				}
			}
			*pucRegBuffer++ = xMBUtilGetBits(ucRegDiscreteBuf, usBitOffset, (UCHAR) (iNDiscrete > 8 ? 8 : iNDiscrete));
			iNDiscrete -= 8;
			usBitOffset += 8;
		}
	}
	else {
		eStatus = MB_ENOREG;
	}
	LOGI("eMBRegDiscreteCB: usAddress: 0x%04X, usNRegs: 0x%04X", usAddress, usNDiscrete);
	return eStatus;
}
/**********************************************************************************/

/**
 * @brief       注册寄存器读写处理回调(参数为null表示使用协议栈的处理接口)
 * @param[in]	ctx                 mbSlave handle
 * @param[in]	eMBRegInputCB       输入寄存器
 * @param[in]	eMBRegHoldingCB     保持寄存器
 * @param[in]	eMBRegCoilsCB       线圈寄存器
 * @param[in]	eMBRegDiscreteCB    离散寄存器
 */
void mbSlave_register_reg_callback(mbSlave_ctx* const ctx,
	eMBRegInputCB_t eMBRegInputCB,
	eMBRegHoldingCB_t eMBRegHoldingCB,
	eMBRegCoilsCB_t eMBRegCoilsCB,
	eMBRegDiscreteCB_t eMBRegDiscreteCB)
{
	ctx->eMBRegInputCB = eMBRegInputCB ? eMBRegInputCB : eMBRegInput_origin_callback;
	ctx->eMBRegHoldingCB = eMBRegHoldingCB ? eMBRegHoldingCB : eMBRegHolding_origin_callback;
	ctx->eMBRegCoilsCB = eMBRegCoilsCB ? eMBRegCoilsCB : eMBRegCoils_origin_callback;
	ctx->eMBRegDiscreteCB = eMBRegDiscreteCB ? eMBRegDiscreteCB : eMBRegDiscrete_origin_callback;
}

BOOL mbSlave_register_input_reg_callback(mbSlave_ctx* const ctx, USHORT regAddr, inputReg_r_cb_t cb)
{
	if (!ctx || !cb) {
		return FALSE;
	}

	/* 首次注册时创建所有寄存器回调函数指针,并初始化为NULL */
	if (!ctx->inputReg_r_cb_list) {
		ctx->inputReg_r_cb_list = eMB_Malloc(sizeof(inputReg_r_cb_t) * ctx->inputReg.size);
		if (!ctx->inputReg_r_cb_list) {
			return FALSE;
		}
		for (size_t i = 0; i < ctx->inputReg.size; i++) {
			ctx->inputReg_r_cb_list[i] = NULL;
		}
	}

	if ((regAddr >= ctx->inputReg.startAddr) && (regAddr <= ctx->inputReg.startAddr + ctx->inputReg.size)) {
		ctx->inputReg_r_cb_list[regAddr - ctx->inputReg.startAddr] = cb;
		return TRUE;
	}
	return FALSE;
}
BOOL mbSlave_register_hold_reg_callback(mbSlave_ctx* const ctx, USHORT regAddr, holdReg_rw_cb_t cb)
{
	if (!ctx || !cb) {
		return FALSE;
	}

	/* 首次注册时创建所有寄存器回调函数指针,并初始化为NULL */
	if (!ctx->holdReg_rw_cb_list) {
		ctx->holdReg_rw_cb_list = eMB_Malloc(sizeof(holdReg_rw_cb_t) * ctx->holdReg.size);
		if (!ctx->holdReg_rw_cb_list) {
			return FALSE;
		}
		for (size_t i = 0; i < ctx->holdReg.size; i++) {
			ctx->holdReg_rw_cb_list[i] = NULL;
		}
	}

	if ((regAddr >= ctx->holdReg.startAddr) && (regAddr <= ctx->holdReg.startAddr + ctx->holdReg.size)) {
		ctx->holdReg_rw_cb_list[regAddr - ctx->holdReg.startAddr] = cb;
		return TRUE;
	}
	return FALSE;
}
BOOL mbSlave_register_coils_reg_callback(mbSlave_ctx* const ctx, USHORT regAddr, coilsReg_rw_cb_t cb)
{
	if (!ctx || !cb) {
		return FALSE;
	}

	/* 首次注册时创建所有寄存器回调函数指针,并初始化为NULL */
	if (!ctx->coilsReg_rw_cb_list) {
		ctx->coilsReg_rw_cb_list = eMB_Malloc(sizeof(coilsReg_rw_cb_t) * ctx->coilsReg.size);
		if (!ctx->coilsReg_rw_cb_list) {
			return FALSE;
		}
		for (size_t i = 0; i < ctx->coilsReg.size; i++) {
			ctx->coilsReg_rw_cb_list[i] = NULL;
		}
	}

	if ((regAddr >= ctx->coilsReg.startAddr) && (regAddr <= ctx->coilsReg.startAddr + ctx->coilsReg.size)) {
		ctx->coilsReg_rw_cb_list[regAddr - ctx->coilsReg.startAddr] = cb;
		return TRUE;
	}
	return FALSE;
}
BOOL mbSlave_register_discrete_reg_callback(mbSlave_ctx* const ctx, USHORT regAddr, discreteReg_r_cb_t cb)
{
	if (!ctx || !cb) {
		return FALSE;
	}

	/* 首次注册时创建所有寄存器回调函数指针,并初始化为NULL */
	if (!ctx->discreteReg_r_cb_list) {
		ctx->discreteReg_r_cb_list = eMB_Malloc(sizeof(discreteReg_r_cb_t) * ctx->discreteReg.size);
		if (!ctx->discreteReg_r_cb_list) {
			return FALSE;
		}
		for (size_t i = 0; i < ctx->discreteReg.size; i++) {
			ctx->discreteReg_r_cb_list[i] = NULL;
		}
	}

	if ((regAddr >= ctx->discreteReg.startAddr) && (regAddr <= ctx->discreteReg.startAddr + ctx->discreteReg.size)) {
		ctx->discreteReg_r_cb_list[regAddr - ctx->discreteReg.startAddr] = cb;
		return TRUE;
	}
	return FALSE;
}
void mbSlave_mapping_input_reg(mbSlave_ctx* const ctx, USHORT* const pRegBuf, USHORT startAddr, USHORT size)
{
	assert(ctx && pRegBuf);
	assert(size > 0);
	ctx->inputReg.pBuf = pRegBuf;
	ctx->inputReg.startAddr = startAddr;
	ctx->inputReg.size = size;
}
void mbSlave_mapping_hold_reg(mbSlave_ctx* const ctx, USHORT* const pRegBuf, USHORT startAddr, USHORT size)
{
	assert(ctx && pRegBuf);
	assert(size > 0);
	ctx->holdReg.pBuf = pRegBuf;
	ctx->holdReg.startAddr = startAddr;
	ctx->holdReg.size = size;
}
void mbSlave_mapping_coils_reg(mbSlave_ctx* const ctx, UCHAR* const pRegBuf, USHORT startAddr, USHORT size)
{
	assert(ctx && pRegBuf);
	assert(size > 0);
	ctx->coilsReg.pBuf = pRegBuf;
	ctx->coilsReg.startAddr = startAddr;
	ctx->coilsReg.size = size;
}
void mbSlave_mapping_discrete_reg(mbSlave_ctx* const ctx, UCHAR* const pRegBuf, USHORT startAddr, USHORT size)
{
	assert(ctx && pRegBuf);
	assert(size > 0);
	ctx->discreteReg.pBuf = pRegBuf;
	ctx->discreteReg.startAddr = startAddr;
	ctx->discreteReg.size = size;
}